﻿using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using SomeGame.Actors.Components;

namespace SomeGame.Tools {

	//=====( Begin Screen-Related )===================================================================

	public static class GraphicsHelper {

		/// <summary>
		///     Produces a letterbox if the screen isn't capable of 16:9.
		/// </summary>
		public static Rectangle SetScreenTo720P(GraphicsDeviceManager graphicsDeviceManager) {
			const int desiredWidth = 1280;
			const int desiredHeight = 720;
			//GraphicsAdapter graphicsAdapter = GraphicsAdapter.DefaultAdapter;
			int currentScreenWidth = graphicsDeviceManager.GraphicsDevice.Viewport.Width; //graphicsAdapter.CurrentDisplayMode.Width;
			int currentScreenHeight = graphicsDeviceManager.GraphicsDevice.Viewport.Height; //graphicsAdapter.CurrentDisplayMode.Height;
			int gameHeight = currentScreenHeight*desiredWidth/currentScreenWidth;
			graphicsDeviceManager.PreferredBackBufferWidth = desiredWidth;
			graphicsDeviceManager.PreferredBackBufferHeight = gameHeight;
			graphicsDeviceManager.ApplyChanges();
			return new Rectangle(0, (int)((gameHeight-desiredHeight)*.5f), desiredWidth, desiredHeight);
		}

		/// <summary>
		///     XNA is locked at 60 fps for desktop, so any movement per frame only needs to know the speed as pixels per second.
		/// </summary>
		public static float PixelsPerFrameAt60Fps(float pixelsPerSecond) {
			return pixelsPerSecond*0.0167f; // Same as dividing by 60.
		}

		//=====( End Screen-Related )====================================================================
		/////////////////////////////////////////////////////////////////////////////////////////////////
		//=====( Begin Geometry-Related )================================================================

        // TODO: Should there be a 'weapon' class?
		public static Vector2[] GetBulletPath(Body playerBody) {
			/*
			 * Bullets are so fast they just 'appear' at their end point in one frame
			 * and are adjusted up or down by the gun's scatter angle.
			 */
		    const int spread = 10;
			const float bulletRange = 640f;
			float scatterAngle = GameEngine.Random.Next(-spread, spread+1); // Horizontal is zero degrees.
			Vector2 barrelEnd = new Vector2(playerBody.FacingDirection == FacingDirection.Right ? playerBody.Bounds.Right : playerBody.Bounds.Left, playerBody.Bounds.Center.Y);
			float angleOfBulletPath = playerBody.FacingDirection == FacingDirection.Right ? scatterAngle : 180-scatterAngle;
			return new[] {barrelEnd, RotatePointOnCircumferenceOfCircle(barrelEnd, bulletRange, MathHelper.ToRadians(angleOfBulletPath))};
		}

		public static Vector2 RotatePointOnCircumferenceOfCircle(Vector2 origin, float radius, double angle) {
			float x = (float)(Math.Cos(angle)*radius+origin.X);
			float y = (float)(Math.Sin(angle)*radius+origin.Y);
			return new Vector2(x, y);
		}

		public static bool LineSegmentIntersectsRectangle(Rectangle bounds, Vector2 v1, Vector2 v2) {
			// Find min and max X for the segment.
			float minX = v1.X;
			float maxX = v2.X;
			if (v1.X > v2.X) {
				minX = v2.X;
				maxX = v1.X;
			}

			// Find the intersection of the segment's and rectangle's x-projections.
			if (maxX > bounds.Right) {
				maxX = bounds.Right;
			}
			if (minX < bounds.Left) {
				minX = bounds.Left;
			}

			// If their projections do not intersect return false.
			if (minX > maxX) {
				return false;
			}

			// Find corresponding min and max Y for min and max X we found before.
			float minY = v1.Y;
			float maxY = v2.Y;

			float dx = v2.X-v1.X;

			if (Math.Abs(dx) > 0.0000001) {
				float a = (v2.Y-v1.Y)/dx;
				float b = v1.Y-a*v1.X;
				minY = a*minX+b;
				maxY = a*maxX+b;
			}

			if (minY > maxY) {
				float tmp = maxY;
				maxY = minY;
				minY = tmp;
			}

			// Find the intersection of the segment's and rectangle's y-projections.
			if (maxY > bounds.Bottom) {
				maxY = bounds.Bottom;
			}

			if (minY < bounds.Top) {
				minY = bounds.Top;
			}

			// If Y-projections do not intersect return false.
			if (minY > maxY) {
				return false;
			}

			return true;
		}

		//=====( End Geometry-Related )==================================================================

	}

}